package red.stu.mc.api.clone;

import java.util.Calendar;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
import java.util.UUID;

import javax.annotation.Nullable;

import com.google.common.base.Function;
import com.google.common.base.Predicate;

import net.minecraft.block.Block;
import net.minecraft.block.material.Material;
import net.minecraft.block.state.IBlockState;
import net.minecraft.crash.CrashReport;
import net.minecraft.crash.CrashReportCategory;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.network.Packet;
import net.minecraft.profiler.Profiler;
import net.minecraft.scoreboard.Scoreboard;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.EnumParticleTypes;
import net.minecraft.util.SoundCategory;
import net.minecraft.util.SoundEvent;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.util.math.Vec3d;
import net.minecraft.village.VillageCollection;
import net.minecraft.world.DifficultyInstance;
import net.minecraft.world.EnumDifficulty;
import net.minecraft.world.EnumSkyBlock;
import net.minecraft.world.Explosion;
import net.minecraft.world.GameRules;
import net.minecraft.world.IWorldEventListener;
import net.minecraft.world.MinecraftException;
import net.minecraft.world.NextTickListEntry;
import net.minecraft.world.WorldProvider;
import net.minecraft.world.WorldType;
import net.minecraft.world.biome.Biome;
import net.minecraft.world.biome.BiomeProvider;
import net.minecraft.world.border.WorldBorder;
import net.minecraft.world.chunk.Chunk;
import net.minecraft.world.chunk.IChunkProvider;
import net.minecraft.world.gen.structure.StructureBoundingBox;
import net.minecraft.world.storage.ISaveHandler;
import net.minecraft.world.storage.MapStorage;
import net.minecraft.world.storage.WorldInfo;
import net.minecraft.world.storage.WorldSavedData;
import net.minecraft.world.storage.loot.LootTableManager;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;

public class World {

	public net.minecraft.world.World instance;

	public World(net.minecraft.world.World instance) {
		this.instance = instance;
	}

	public List<Entity> getLoadedEntityList() {
		return instance.loadedEntityList;
	}

	public List<TileEntity> getLoadedTileEntityList() {
		return instance.loadedTileEntityList;
	}

	public List<TileEntity> getTickableTileEntities() {
		return instance.tickableTileEntities;
	}

	public List<EntityPlayer> getPlayerEntities() {
		return instance.playerEntities;
	}

	public List<Entity> getWeatherEffects() {
		return instance.weatherEffects;
	}

	public float getPrevRainingStrength() {
		return instance.prevRainingStrength;
	}

	public float getRainingStrength() {
		return instance.rainingStrength;
	}

	public float getPrevThunderingStrength() {
		return instance.prevThunderingStrength;
	}

	public float getThunderingStrength() {
		return instance.thunderingStrength;
	}

	public Random getRand() {
		return instance.rand;
	}

	public WorldProvider getProvider() {
		return instance.provider;
	}

	public VillageCollection getVillageCollection() {
		return instance.villageCollection;
	}

	public Profiler getProfiler() {
		return instance.profiler;
	}

	public boolean isRemote() {
		return instance.isRemote;
	}

	public java.util.ArrayList<net.minecraftforge.common.util.BlockSnapshot> getCapturedBlockSnapshots() {
		return instance.capturedBlockSnapshots;
	}

	public Biome getBiome(final BlockPos pos) {
		return instance.getBiome(pos);
	}

	public Biome getBiomeForCoordsBody(final BlockPos pos) {
		return instance.getBiomeForCoordsBody(pos);
	}

	public BiomeProvider getBiomeProvider() {
		return instance.getBiomeProvider();
	}

	public IBlockState getGroundAboveSeaLevel(BlockPos pos) {
		return instance.getGroundAboveSeaLevel(pos);
	}

	/**
	 * 检查给定的块坐标是否有效
	 * 
	 * @param pos
	 * @return
	 */
	public boolean isValid(BlockPos pos) {
		return instance.isValid(pos);
	}

	/**
	 * 方块坐标是否超出了建造高度
	 * 
	 * @param pos
	 * @return
	 */
	public boolean isOutsideBuildHeight(BlockPos pos) {
		return instance.isOutsideBuildHeight(pos);
	}

	/**
	 * 是否为空气方块
	 * 
	 * @param pos
	 * @return
	 */
	public boolean isAirBlock(BlockPos pos) {
		return instance.isAirBlock(pos);
	}

	/**
	 * 方块是否已加载
	 * 
	 * @param pos
	 * @return
	 */
	public boolean isBlockLoaded(BlockPos pos) {
		return instance.isBlockLoaded(pos);
	}

	/**
	 * 方块是否已加载
	 * 
	 * @param pos
	 * @param allowEmpty
	 *            允许空
	 * @return
	 */
	public boolean isBlockLoaded(BlockPos pos, boolean allowEmpty) {
		return instance.isBlockLoaded(pos, allowEmpty);
	}

	/**
	 * 是否已加载指定面积区域
	 * 
	 * @param center
	 *            中心位置
	 * @param radius
	 *            半径
	 * @return
	 */
	public boolean isAreaLoaded(BlockPos center, int radius) {
		return instance.isAreaLoaded(center, radius);
	}

	/**
	 * 是否已加载指定面积区域
	 * 
	 * @param center
	 *            中心位置
	 * @param radius
	 *            半径
	 * @param allowEmpty
	 *            允许空
	 * @return
	 */
	public boolean isAreaLoaded(BlockPos center, int radius, boolean allowEmpty) {
		return instance.isAreaLoaded(center, radius, allowEmpty);
	}

	/**
	 * 是否已加载指定面积区域
	 * 
	 * @param from
	 *            起始范围位置
	 * @param to
	 *            结束范围位置
	 * @return
	 */
	public boolean isAreaLoaded(BlockPos from, BlockPos to) {
		return instance.isAreaLoaded(from, to);
	}

	/**
	 * 是否已加载指定面积区域
	 * 
	 * @param from
	 *            起始范围位置
	 * @param to
	 *            结束范围位置
	 * @param allowEmpty
	 *            允许空
	 * @return
	 */
	public boolean isAreaLoaded(BlockPos from, BlockPos to, boolean allowEmpty) {
		return instance.isAreaLoaded(from, to, allowEmpty);
	}

	public boolean isAreaLoaded(StructureBoundingBox box) {
		return instance.isAreaLoaded(box);
	}

	public boolean isAreaLoaded(StructureBoundingBox box, boolean allowEmpty) {
		return instance.isAreaLoaded(box, allowEmpty);
	}

	public Chunk getChunkFromBlockCoords(BlockPos pos) {
		return instance.getChunkFromBlockCoords(pos);
	}

	public Chunk getChunkFromChunkCoords(int chunkX, int chunkZ) {
		return instance.getChunkFromChunkCoords(chunkX, chunkZ);
	}

	public boolean isChunkGeneratedAt(int x, int z) {
		return instance.isChunkGeneratedAt(x, z);
	}

	/**
	 * 放置方块<br>
	 * 
	 * 标志1将导致块更新。标志2将向客户端发送更改。
	 * 如果这是客户端世界，则标志4将阻止该块被重新渲染。
	 * 如果这是一个客户端世界，并且标志4是明确的，
	 * 则标志8将强制任何重新呈现在主线程上而不是在工作池中运行。
	 * 标志16将阻止观察员看到这种变化。
	 * flags可以OR-ed
	 * @param pos
	 * @param newState
	 * @param flags
	 * @return
	 */
	public boolean setBlockState(BlockPos pos, IBlockState newState, int flags) {
		return instance.setBlockState(pos, newState, flags);
	}
	
	/**
	 * 标记通知方块<br>
	 * 	从原始setBlockState(BlockPos, IBlockState, int)方法中分离，以便直接发送客户端和物理更新
	 * @param pos
	 * @param chunk
	 * @param iblockstate
	 * @param newState
	 * @param flags
	 */
	public void markAndNotifyBlock(BlockPos pos, @Nullable Chunk chunk, IBlockState iblockstate, IBlockState newState, int flags) {
		instance.markAndNotifyBlock(pos, chunk, iblockstate, newState, flags);
	}
	
	public boolean setBlockToAir(BlockPos pos) {
		return instance.setBlockToAir(pos);
	}
	
	/**
	 * 破坏方块<br>
	 * 设置一个块到空气，但也播放声音和粒子
	 * @param pos
	 * @param dropBlock
	 * @return
	 */
	public boolean destroyBlock(BlockPos pos, boolean dropBlock) {
		return instance.destroyBlock(pos, dropBlock);
	}
	
	/**
	 * 在客户端和服务器上更新块的便利方法
	 * @param pos
	 * @param state
	 * @return
	 */
	public boolean setBlockState(BlockPos pos, IBlockState state) {
		return instance.setBlockState(pos, state);
	}
	
	/**
	 * 标志位于setBlockState
	 * @param pos
	 * @param oldState
	 * @param newState
	 * @param flags
	 */
	public void notifyBlockUpdate(BlockPos pos, IBlockState oldState, IBlockState newState, int flags) {
		instance.notifyBlockUpdate(pos, oldState, newState, flags);
	}
	
	public void notifyNeighborsRespectDebug(BlockPos pos, Block blockType, boolean p_175722_3_) {
		instance.notifyNeighborsRespectDebug(pos, blockType, p_175722_3_);
	}
	
	/**
	 * 将块的垂直线标记为脏
	 * @param x1
	 * @param z1
	 * @param x2
	 * @param z2
	 */
	public void markBlocksDirtyVertical(int x1, int z1, int x2, int z2) {
		instance.markBlocksDirtyVertical(x1, z1, x2, z2);
	}
	
	public void markBlockRangeForRenderUpdate(BlockPos rangeMin, BlockPos rangeMax) {
		instance.markBlockRangeForRenderUpdate(rangeMin, rangeMax);
	}
	
	public void markBlockRangeForRenderUpdate(int x1, int y1, int z1, int x2, int y2, int z2) {
		instance.markBlockRangeForRenderUpdate(x1, y1, z1, x2, y2, z2);
	}
	
	public void updateObservingBlocksAt(BlockPos pos, Block blockType) {
		instance.updateObservingBlocksAt(pos, blockType);
	}
	
	public void notifyNeighborsOfStateChange(BlockPos pos, Block blockType, boolean updateObservers) {
		instance.notifyNeighborsOfStateChange(pos, blockType, updateObservers);
	}
	
	public void notifyNeighborsOfStateExcept(BlockPos pos, Block blockType, EnumFacing skipSide) {
		instance.notifyNeighborsOfStateExcept(pos, blockType, skipSide);
	}
	
	public void neighborChanged(BlockPos pos, final Block p_190524_2_, BlockPos p_190524_3_) {
		instance.neighborChanged(pos, p_190524_2_, p_190524_3_);
	}
	
	public void observedNeighborChanged(BlockPos pos, final Block p_190529_2_, BlockPos p_190529_3_) {
		instance.observedNeighborChanged(pos, p_190529_2_, p_190529_3_);
	}
	
	public boolean isBlockTickPending(BlockPos pos, Block blockType) {
		return instance.isBlockTickPending(pos, blockType);
	}
	
	public boolean canSeeSky(BlockPos pos) {
		return instance.canSeeSky(pos);
	}
	
	public boolean canBlockSeeSky(BlockPos pos) {
		return instance.canBlockSeeSky(pos);
	}
	
	public int getLight(BlockPos pos) {
		return instance.getLight(pos);
	}
	
	public int getLightFromNeighbors(BlockPos pos) {
		return instance.getLightFromNeighbors(pos);
	}
	
	public int getLight(BlockPos pos, boolean checkNeighbors) {
		return instance.getLight(pos, checkNeighbors);
	}
	
	public BlockPos getHeight(BlockPos pos) {
		return instance.getHeight(pos);
	}
	
	public int getHeight(int x, int z) {
		return instance.getHeight(x, z);
	}
	
	@Deprecated
    public int getChunksLowestHorizon(int x, int z) {
		return instance.getChunksLowestHorizon(x, z);
	}
	
	@SideOnly(Side.CLIENT)
    public int getLightFromNeighborsFor(EnumSkyBlock type, BlockPos pos) {
		return instance.getLightFromNeighborsFor(type, pos);
	}
	
	public int getLightFor(EnumSkyBlock type, BlockPos pos) {
		return instance.getLightFor(type, pos);
	}
	
	public void setLightFor(EnumSkyBlock type, BlockPos pos, int lightValue) {
		instance.setLightFor(type, pos, lightValue);
	}
	
	public void notifyLightSet(BlockPos pos) {
		instance.notifyLightSet(pos);
	}
	
	@SideOnly(Side.CLIENT)
    public int getCombinedLight(BlockPos pos, int lightValue) {
		return instance.getCombinedLight(pos, lightValue);
	}
	
	public float getLightBrightness(BlockPos pos) {
		return instance.getLightBrightness(pos);
	}
	
	public IBlockState getBlockState(BlockPos pos) {
		return instance.getBlockState(pos);
	}
	
	public boolean isDaytime() {
		return instance.isDaytime();
	}
	
	@Nullable
    public RayTraceResult rayTraceBlocks(Vec3d start, Vec3d end) {
		return instance.rayTraceBlocks(start, end);
	}
	
	@Nullable
    public RayTraceResult rayTraceBlocks(Vec3d start, Vec3d end, boolean stopOnLiquid) {
		return instance.rayTraceBlocks(start, end, stopOnLiquid);
	}
	
	/**
     * Performs a raycast against all blocks in the world. Args : Vec1, Vec2, stopOnLiquid,
     * ignoreBlockWithoutBoundingBox, returnLastUncollidableBlock
     */
    @Nullable
    public RayTraceResult rayTraceBlocks(Vec3d vec31, Vec3d vec32, boolean stopOnLiquid, boolean ignoreBlockWithoutBoundingBox, boolean returnLastUncollidableBlock) {
    	return instance.rayTraceBlocks(vec31, vec32, stopOnLiquid, ignoreBlockWithoutBoundingBox, returnLastUncollidableBlock);
    }
    
    /**
     * 在给定的块位置的中心为玩家播放指定的声音
     * @param player
     * @param pos
     * @param soundIn
     * @param category
     * @param volume
     * @param pitch
     */
    public void playSound(@Nullable EntityPlayer player, BlockPos pos, SoundEvent soundIn, SoundCategory category, float volume, float pitch) {
    	instance.playSound(player, pos, soundIn, category, volume, pitch);
    }
	
    public void playSound(@Nullable EntityPlayer player, double x, double y, double z, SoundEvent soundIn, SoundCategory category, float volume, float pitch) {
    	instance.playSound(player, x, y, z, soundIn, category, volume, pitch);
    }
    
    public void playSound(double x, double y, double z, SoundEvent soundIn, SoundCategory category, float volume, float pitch, boolean distanceDelay) {
    	instance.playSound(x, y, z, soundIn, category, volume, pitch, distanceDelay);
    }
    
    public void playRecord(BlockPos blockPositionIn, @Nullable SoundEvent soundEventIn) {
    	instance.playRecord(blockPositionIn, soundEventIn);
    }
    
    public void spawnParticle(EnumParticleTypes particleType, double xCoord, double yCoord, double zCoord, double xSpeed, double ySpeed, double zSpeed, int... parameters) {
    	instance.spawnParticle(particleType, xCoord, yCoord, zCoord, xSpeed, ySpeed, zSpeed, parameters);
    }
    
    /**
     * Spawns particles that will always show regardless of the Video Settings -> Particles setting. Range restrictions
     * still apply.
     */
    public void spawnAlwaysVisibleParticle(int p_190523_1_, double p_190523_2_, double p_190523_4_, double p_190523_6_, double p_190523_8_, double p_190523_10_, double p_190523_12_, int... p_190523_14_) {
    	instance.spawnAlwaysVisibleParticle(p_190523_1_, p_190523_2_, p_190523_4_, p_190523_6_, p_190523_8_, p_190523_10_, p_190523_12_, p_190523_14_);
    }
    
    @SideOnly(Side.CLIENT)
    public void spawnParticle(EnumParticleTypes particleType, boolean ignoreRange, double xCoord, double yCoord, double zCoord, double xSpeed, double ySpeed, double zSpeed, int... parameters) {
    	instance.spawnParticle(particleType, ignoreRange, xCoord, yCoord, zCoord, xSpeed, ySpeed, zSpeed, parameters);
    }
    
    /**
     * adds a lightning bolt to the list of lightning bolts in this world.
     */
    public boolean addWeatherEffect(Entity entityIn) {
    	return instance.addWeatherEffect(entityIn);
    }
    
    /**
     * Called when an entity is spawned in the world. This includes players.
     */
    public boolean spawnEntity(Entity entityIn) {
    	return instance.spawnEntity(entityIn);
    }
    
    public void onEntityAdded(Entity entityIn) {
    	instance.onEntityAdded(entityIn);
    }
    
    public void onEntityRemoved(Entity entityIn) {
    	instance.onEntityRemoved(entityIn);
    }
    
    /**
     * Schedule the entity for removal during the next tick. Marks the entity dead in anticipation.
     */
    public void removeEntity(Entity entityIn) {
    	instance.removeEntity(entityIn);
    }
    
    /**
     * 不要使用此方法移除正常实体
     */
    public void removeEntityDangerously(Entity entityIn) {
    	instance.removeEntityDangerously(entityIn);
    }
    
    /**
     * Add a world event listener
     */
    public void addEventListener(IWorldEventListener listener) {
    	instance.addEventListener(listener);
    }
    
    /**
     * Gets a list of bounding boxes that intersect with the provided AABB.
     */
    public List<AxisAlignedBB> getCollisionBoxes(@Nullable Entity entityIn, AxisAlignedBB aabb) {
    	return instance.getCollisionBoxes(entityIn, aabb);
    }
    
    /**
     * Remove a world event listener
     */
    public void removeEventListener(IWorldEventListener listener) {
    	instance.removeEventListener(listener);
    }
    
    public boolean isInsideWorldBorder(Entity p_191503_1_) {
    	return instance.isInsideWorldBorder(p_191503_1_);
    }
    
    /**
     * 如果给定Bbox与任何块发生冲突，则返回true。
     * Returns true if the given bbox collides with any block.
     */
    public boolean collidesWithAnyBlock(AxisAlignedBB bbox) {
    	return instance.collidesWithAnyBlock(bbox);
    }
    
    /**
     * Returns the amount of skylight subtracted for the current time
     */
    public int calculateSkylightSubtracted(float partialTicks) {
    	return instance.calculateSkylightSubtracted(partialTicks);
    }
    
    /**
     * 这个维度的当前太阳亮度因子。
     * 0.0F意味着根本没有光，
     * 1.0F意味着最大的阳光。强烈推荐像太阳能电池板一样进行阳光检测
     * 
     * The current sun brightness factor for this dimension.
     * 0.0f means no light at all, and 1.0f means maximum sunlight.
     * Highly recommended for sunlight detection like solar panel.
     *
     * @return The current brightness factor
     * */
    public float getSunBrightnessFactor(float partialTicks) {
    	return instance.getSunBrightnessFactor(partialTicks);
    }
    
    /**
     * 返回太阳亮度-检查时间，雨和雷声
     * Returns the sun brightness - checks time of day, rain and thunder
     */
    @SideOnly(Side.CLIENT)
    public float getSunBrightness(float partialTicks) {
    	return instance.getSunBrightness(partialTicks);
    }
    
    @SideOnly(Side.CLIENT)
    public float getSunBrightnessBody(float partialTicks) {
    	return instance.getSunBrightnessBody(partialTicks);
    }
    
    /**
     * 计算天空盒的颜色
     * Calculates the color for the skybox
     */
    @SideOnly(Side.CLIENT)
    public Vec3d getSkyColor(Entity entityIn, float partialTicks) {
    	return instance.getSkyColor(entityIn, partialTicks);
    }
    
    @SideOnly(Side.CLIENT)
    public Vec3d getSkyColorBody(Entity entityIn, float partialTicks) {
    	return instance.getSkyColorBody(entityIn, partialTicks);
    }
    
    /**
     * calls calculateCelestialAngle
     */
    public float getCelestialAngle(float partialTicks) {
    	return instance.getCelestialAngle(partialTicks);
    }
    
    @SideOnly(Side.CLIENT)
    public int getMoonPhase() {
    	return instance.getMoonPhase();
    }
    
    /**
     * gets the current fullness of the moon expressed as a float between 1.0 and 0.0, in steps of .25
     */
    public float getCurrentMoonPhaseFactor() {
    	return instance.getCurrentMoonPhaseFactor();
    }
    
    public float getCurrentMoonPhaseFactorBody() {
    	return instance.getCurrentMoonPhaseFactorBody();
    }
    
    /**
     * Return getCelestialAngle()*2*PI
     */
    public float getCelestialAngleRadians(float partialTicks) {
    	return instance.getCelestialAngleRadians(partialTicks);
    }
    
    @SideOnly(Side.CLIENT)
    public Vec3d getCloudColour(float partialTicks) {
    	return instance.getCloudColour(partialTicks);
    }
    
    @SideOnly(Side.CLIENT)
    public Vec3d getCloudColorBody(float partialTicks) {
    	return instance.getCloudColorBody(partialTicks);
    }
    
    /**
     * Returns vector(ish) with R/G/B for fog
     */
    @SideOnly(Side.CLIENT)
    public Vec3d getFogColor(float partialTicks) {
    	return instance.getFogColor(partialTicks);
    }
    
    public BlockPos getPrecipitationHeight(BlockPos pos) {
    	return instance.getPrecipitationHeight(pos);
    }
    
    /**
     * Finds the highest block on the x and z coordinate that is solid or liquid, and returns its y coord.
     */
    public BlockPos getTopSolidOrLiquidBlock(BlockPos pos) {
    	return instance.getTopSolidOrLiquidBlock(pos);
    }
    
    /**
     * How bright are stars in the sky
     */
    @SideOnly(Side.CLIENT)
    public float getStarBrightness(float partialTicks) {
    	return instance.getStarBrightness(partialTicks);
    }
    
    @SideOnly(Side.CLIENT)
    public float getStarBrightnessBody(float partialTicks) {
    	return instance.getStarBrightnessBody(partialTicks);
    }
    
    /**
     * Returns true if the identified block is scheduled to be updated.
     */
    public boolean isUpdateScheduled(BlockPos pos, Block blk)
    {
    	return instance.isUpdateScheduled(pos, blk);
    }

    public void scheduleUpdate(BlockPos pos, Block blockIn, int delay)
    {
    	instance.scheduleUpdate(pos, blockIn, delay);
    }

    public void updateBlockTick(BlockPos pos, Block blockIn, int delay, int priority)
    {
    	instance.updateBlockTick(pos, blockIn, delay, priority);
    }

    /**
     * Called by CommandClone and AnvilChunkLoader to force a block update.
     */
    public void scheduleBlockUpdate(BlockPos pos, Block blockIn, int delay, int priority)
    {
    	instance.scheduleBlockUpdate(pos, blockIn, delay, priority);
    }
    
    /**
     * Updates (and cleans up) entities and tile entities
     */
    public void updateEntities() {
    	instance.updateEntities();
    }
    
    public boolean addTileEntity(TileEntity tile) {
    	return instance.addTileEntity(tile);
    }
    
    public void addTileEntities(Collection<TileEntity> tileEntityCollection) {
    	instance.addTileEntities(tileEntityCollection);
    }
    
    /**
     * Forcefully updates the entity.
     */
    public void updateEntity(Entity ent) {
    	instance.updateEntity(ent);
    }
    
    /**
     * Updates the entity in the world if the chunk the entity is in is currently loaded or its forced to update.
     */
    public void updateEntityWithOptionalForce(Entity entityIn, boolean forceUpdate) {
    	instance.updateEntityWithOptionalForce(entityIn, forceUpdate);
    }
    
    /**
     * Returns true if there are no solid, live entities in the specified AxisAlignedBB
     */
    public boolean checkNoEntityCollision(AxisAlignedBB bb) {
    	return instance.checkNoEntityCollision(bb);
    }
    
    /**
     * Returns true if there are no solid, live entities in the specified AxisAlignedBB, excluding the given entity
     */
    public boolean checkNoEntityCollision(AxisAlignedBB bb, @Nullable Entity entityIn) {
    	return instance.checkNoEntityCollision(bb, entityIn);
    }
    
    /**
     * Returns true if there are any blocks in the region constrained by an AxisAlignedBB
     */
    public boolean checkBlockCollision(AxisAlignedBB bb) {
    	return instance.checkBlockCollision(bb);
    }
    
    /**
     * Checks if any of the blocks within the aabb are liquids.
     */
    public boolean containsAnyLiquid(AxisAlignedBB bb) {
    	return instance.containsAnyLiquid(bb);
    }
    
    public boolean isFlammableWithin(AxisAlignedBB bb) {
    	return instance.isFlammableWithin(bb);
    }
    
    /**
     * handles the acceleration of an object whilst in water. Not sure if it is used elsewhere.
     */
    public boolean handleMaterialAcceleration(AxisAlignedBB bb, Material materialIn, Entity entityIn) {
    	return instance.handleMaterialAcceleration(bb, materialIn, entityIn);
    }
    
    /**
     * Returns true if the given bounding box contains the given material
     */
    public boolean isMaterialInBB(AxisAlignedBB bb, Material materialIn) {
    	return instance.isMaterialInBB(bb, materialIn);
    }
    
    /**
     * Creates an explosion in the world.
     */
    public Explosion createExplosion(@Nullable Entity entityIn, double x, double y, double z, float strength, boolean isSmoking) {
    	return instance.createExplosion(entityIn, x, y, z, strength, isSmoking);
    }
    
    /**
     * returns a new explosion. Does initiation (at time of writing Explosion is not finished)
     */
    public Explosion newExplosion(@Nullable Entity entityIn, double x, double y, double z, float strength, boolean isFlaming, boolean isSmoking) {
    	return instance.newExplosion(entityIn, x, y, z, strength, isFlaming, isSmoking);
    }
    
    /**
     * Gets the percentage of real blocks within within a bounding box, along a specified vector.
     */
    public float getBlockDensity(Vec3d vec, AxisAlignedBB bb) {
    	return instance.getBlockDensity(vec, bb);
    }
    
    /**
     * Attempts to extinguish a fire
     */
    public boolean extinguishFire(@Nullable EntityPlayer player, BlockPos pos, EnumFacing side) {
    	return instance.extinguishFire(player, pos, side);
    }
    
    /**
     * This string is 'All: (number of loaded entities)' Viewable by press ing F3
     */
    @SideOnly(Side.CLIENT)
    public String getDebugLoadedEntities() {
    	return instance.getDebugLoadedEntities();
    }
    
    /**
     * Returns the name of the current chunk provider, by calling chunkprovider.makeString()
     */
    @SideOnly(Side.CLIENT)
    public String getProviderName() {
    	return instance.getProviderName();
    }
    
    @Nullable
    public TileEntity getTileEntity(BlockPos pos) {
    	return instance.getTileEntity(pos);
    }
    
    public void setTileEntity(BlockPos pos, @Nullable TileEntity tileEntityIn) {
    	instance.setTileEntity(pos, tileEntityIn);
    }
    
    public void removeTileEntity(BlockPos pos) {
    	instance.removeTileEntity(pos);
    }
    
    /**
     * Adds the specified TileEntity to the pending removal list.
     */
    public void markTileEntityForRemoval(TileEntity tileEntityIn) {
    	instance.markTileEntityForRemoval(tileEntityIn);
    }
    
    public boolean isBlockFullCube(BlockPos pos) {
    	return instance.isBlockFullCube(pos);
    }
    
    /**
     * Checks if a block's material is opaque, and that it takes up a full cube
     */
    public boolean isBlockNormalCube(BlockPos pos, boolean _default) {
    	return instance.isBlockNormalCube(pos, _default);
    }
    
    /**
     * Called on construction of the World class to setup the initial skylight values
     */
    public void calculateInitialSkylight() {
    	instance.calculateInitialSkylight();
    }
    
    /**
     * first boolean for hostile mobs and second for peaceful mobs
     */
    public void setAllowedSpawnTypes(boolean hostile, boolean peaceful) {
    	instance.setAllowedSpawnTypes(hostile, peaceful);
    }
    
    /**
     * Runs a single tick for the world
     */
    public void tick() {
    	instance.tick();
    }
    
    public void calculateInitialWeatherBody() {
    	instance.calculateInitialWeatherBody();
    }
    
    public void updateWeatherBody() {
    	instance.updateWeatherBody();
    }
    
    public void immediateBlockTick(BlockPos pos, IBlockState state, Random random) {
    	instance.immediateBlockTick(pos, state, random);
    }
    
    public boolean canBlockFreezeWater(BlockPos pos) {
    	return instance.canBlockFreezeWater(pos);
    }
    
    public boolean canBlockFreezeNoWater(BlockPos pos) {
    	return instance.canBlockFreezeNoWater(pos);
    }
    
    /**
     * Checks to see if a given block is both water and cold enough to freeze.
     */
    public boolean canBlockFreeze(BlockPos pos, boolean noWaterAdj) {
    	return instance.canBlockFreeze(pos, noWaterAdj);
    }
    
    public boolean canBlockFreezeBody(BlockPos pos, boolean noWaterAdj) {
    	return instance.canBlockFreezeBody(pos, noWaterAdj);
    }
    
    /**
     * Checks to see if a given block can accumulate snow from it snowing
     */
    public boolean canSnowAt(BlockPos pos, boolean checkLight) {
    	return instance.canSnowAt(pos, checkLight);
    }
    
    public boolean canSnowAtBody(BlockPos pos, boolean checkLight) {
    	return instance.canSnowAtBody(pos, checkLight);
    }
    
    public boolean checkLight(BlockPos pos) {
    	return instance.checkLight(pos);
    }
    
    public boolean checkLightFor(EnumSkyBlock lightType, BlockPos pos) {
    	return instance.checkLightFor(lightType, pos);
    }
    
    /**
     * Runs through the list of updates to run and ticks them
     */
    public boolean tickUpdates(boolean runAllPending) {
    	return instance.tickUpdates(runAllPending);
    }
    
    @Nullable
    public List<NextTickListEntry> getPendingBlockUpdates(Chunk chunkIn, boolean remove) {
    	return instance.getPendingBlockUpdates(chunkIn, remove);
    }
    
    @Nullable
    public List<NextTickListEntry> getPendingBlockUpdates(StructureBoundingBox structureBB, boolean remove) {
    	return instance.getPendingBlockUpdates(structureBB, remove);
    }
    
    /**
     * Will get all entities within the specified AABB excluding the one passed into it. Args: entityToExclude, aabb
     */
    public List<Entity> getEntitiesWithinAABBExcludingEntity(@Nullable Entity entityIn, AxisAlignedBB bb) {
    	return instance.getEntitiesWithinAABBExcludingEntity(entityIn, bb);
    }
    
    /**
     * Gets all entities within the specified AABB excluding the one passed into it.
     */
    public List<Entity> getEntitiesInAABBexcluding(@Nullable Entity entityIn, AxisAlignedBB boundingBox, @Nullable Predicate <? super Entity > predicate) {
    	return instance.getEntitiesInAABBexcluding(entityIn, boundingBox, predicate);
    }
    
    public <T extends Entity> List<T> getEntities(Class <? extends T > entityType, Predicate <? super T > filter) {
    	return instance.getEntities(entityType, filter);
    }
    
    public <T extends Entity> List<T> getPlayers(Class <? extends T > playerType, Predicate <? super T > filter) {
    	return instance.getPlayers(playerType, filter);
    }
    
    public <T extends Entity> List<T> getEntitiesWithinAABB(Class <? extends T > classEntity, AxisAlignedBB bb) {
    	return instance.getEntitiesWithinAABB(classEntity, bb);
    }
    
    public <T extends Entity> List<T> getEntitiesWithinAABB(Class <? extends T > clazz, AxisAlignedBB aabb, @Nullable Predicate <? super T > filter) {
    	return instance.getEntitiesWithinAABB(clazz, aabb, filter);
    }
    
    @Nullable
    public <T extends Entity> T findNearestEntityWithinAABB(Class <? extends T > entityType, AxisAlignedBB aabb, T closestTo) {
    	return instance.findNearestEntityWithinAABB(entityType, aabb, closestTo);
    }
    
    /**
     * Returns the Entity with the given ID, or null if it doesn't exist in this World.
     */
    @Nullable
    public Entity getEntityByID(int id) {
    	return instance.getEntityByID(id);
    }
    
    public void markChunkDirty(BlockPos pos, TileEntity unusedTileEntity) {
    	instance.markChunkDirty(pos, unusedTileEntity);
    }
    
    /**
     * Counts how many entities of an entity class exist in the world.
     */
    public int countEntities(Class<?> entityType) {
    	return instance.countEntities(entityType);
    }
    
    public void loadEntities(Collection<Entity> entityCollection) {
    	instance.loadEntities(entityCollection);
    }
    
    public void unloadEntities(Collection<Entity> entityCollection) {
    	instance.unloadEntities(entityCollection);
    }
    
    public boolean mayPlace(Block blockIn, BlockPos pos, boolean p_190527_3_, EnumFacing sidePlacedOn, @Nullable Entity placer) {
    	return instance.mayPlace(blockIn, pos, p_190527_3_, sidePlacedOn, placer);
    }
    
    public int getSeaLevel() {
    	return instance.getSeaLevel();
    }
    
    /**
     * Warning this value may not be respected in all cases as it is still hardcoded in many places.
     */
    public void setSeaLevel(int seaLevelIn) {
    	instance.setSeaLevel(seaLevelIn);
    }
    
    public int getStrongPower(BlockPos pos, EnumFacing direction) {
    	return instance.getStrongPower(pos, direction);
    }
    
    public WorldType getWorldType() {
    	return instance.getWorldType();
    }
    
    /**
     * Returns the single highest strong power out of all directions using getStrongPower(BlockPos, EnumFacing)
     */
    public int getStrongPower(BlockPos pos) {
    	return instance.getStrongPower(pos);
    }
    
    public boolean isSidePowered(BlockPos pos, EnumFacing side) {
    	return instance.isSidePowered(pos, side);
    }
    
    public int getRedstonePower(BlockPos pos, EnumFacing facing) {
    	return instance.getRedstonePower(pos, facing);
    }
    
    public boolean isBlockPowered(BlockPos pos) {
    	return instance.isBlockPowered(pos);
    }
    
    /**
     * 检查指定块或其邻居是否由相邻块提供动力。使用如TNT和门的块
     * Checks if the specified block or its neighbors are powered by a neighboring block. Used by blocks like TNT and
     * Doors.
     */
    public int isBlockIndirectlyGettingPowered(BlockPos pos) {
    	return instance.isBlockIndirectlyGettingPowered(pos);
    }
    
    /**
     * Gets the closest player to the entity within the specified distance.
     */
    @Nullable
    public EntityPlayer getClosestPlayerToEntity(Entity entityIn, double distance) {
    	return instance.getClosestPlayerToEntity(entityIn, distance);
    }
    
    @Nullable
    public EntityPlayer getNearestPlayerNotCreative(Entity entityIn, double distance) {
    	return instance.getNearestPlayerNotCreative(entityIn, distance);
    }
    
    @Nullable
    public EntityPlayer getClosestPlayer(double posX, double posY, double posZ, double distance, boolean spectator) {
    	return instance.getClosestPlayer(posX, posY, posZ, distance, spectator);
    }
    
    @Nullable
    public EntityPlayer getClosestPlayer(double x, double y, double z, double p_190525_7_, Predicate<Entity> p_190525_9_) {
    	return instance.getClosestPlayer(x, y, z, p_190525_7_, p_190525_9_);
    }
    
    public boolean isAnyPlayerWithinRangeAt(double x, double y, double z, double range) {
    	return instance.isAnyPlayerWithinRangeAt(x, y, z, range);
    }
    
    @Nullable
    public EntityPlayer getNearestAttackablePlayer(Entity entityIn, double maxXZDistance, double maxYDistance) {
    	return instance.getNearestAttackablePlayer(entityIn, maxXZDistance, maxYDistance);
    }
    
    @Nullable
    public EntityPlayer getNearestAttackablePlayer(BlockPos pos, double maxXZDistance, double maxYDistance) {
    	return instance.getNearestAttackablePlayer(pos, maxXZDistance, maxYDistance);
    }
    
    @Nullable
    public EntityPlayer getNearestAttackablePlayer(double posX, double posY, double posZ, double maxXZDistance, double maxYDistance, @Nullable Function<EntityPlayer, Double> playerToDouble, @Nullable Predicate<EntityPlayer> p_184150_12_) {
    	return instance.getNearestAttackablePlayer(posX, posY, posZ, maxXZDistance, maxYDistance, playerToDouble, p_184150_12_);
    }
    
    /**
     * Find a player by name in this world.
     */
    @Nullable
    public EntityPlayer getPlayerEntityByName(String name) {
    	return instance.getPlayerEntityByName(name);
    }
    
    @Nullable
    public EntityPlayer getPlayerEntityByUUID(UUID uuid) {
    	return instance.getPlayerEntityByUUID(uuid);
    }
    
    /**
     * If on MP, sends a quitting packet.
     */
    @SideOnly(Side.CLIENT)
    public void sendQuittingDisconnectingPacket() {
    	instance.sendQuittingDisconnectingPacket();
    }
    
    /**
     * Checks whether the session lock file was modified by another process
     */
    public void checkSessionLock() throws MinecraftException {
    	instance.checkSessionLock();
    }
    
    @SideOnly(Side.CLIENT)
    public void setTotalWorldTime(long worldTime) {
    	instance.setTotalWorldTime(worldTime);
    }
    
    /**
     * gets the random world seed
     */
    public long getSeed() {
    	return instance.getSeed();
    }
    
    public long getTotalWorldTime() {
    	return instance.getTotalWorldTime();
    }
    
    public long getWorldTime() {
    	return instance.getWorldTime();
    }
    
    /**
     * Sets the world time.
     */
    public void setWorldTime(long time) {
    	instance.setWorldTime(time);
    }
    
    /**
     * Gets the spawn point in the world
     */
    public BlockPos getSpawnPoint() {
    	return instance.getSpawnPoint();
    }
    
    public void setSpawnPoint(BlockPos pos) {
    	instance.setSpawnPoint(pos);
    }
    
    /**
     * spwans an entity and loads surrounding chunks
     */
    @SideOnly(Side.CLIENT)
    public void joinEntityInSurroundings(Entity entityIn) {
    	instance.joinEntityInSurroundings(entityIn);
    }
    
    public boolean isBlockModifiable(EntityPlayer player, BlockPos pos) {
    	return instance.isBlockModifiable(player, pos);
    }
    
    public boolean canMineBlockBody(EntityPlayer player, BlockPos pos) {
    	return instance.canMineBlockBody(player, pos);
    }
    
    /**
     * sends a Packet 38 (Entity Status) to all tracked players of that entity
     */
    public void setEntityState(Entity entityIn, byte state) {
    	instance.setEntityState(entityIn, state);
    }
    
    /**
     * gets the world's chunk provider
     */
    public IChunkProvider getChunkProvider() {
    	return instance.getChunkProvider();
    }
    
    public void addBlockEvent(BlockPos pos, Block blockIn, int eventID, int eventParam) {
    	instance.addBlockEvent(pos, blockIn, eventID, eventParam);
    }
    
    /**
     * Returns this world's current save handler
     */
    public ISaveHandler getSaveHandler() {
    	return instance.getSaveHandler();
    }
    
    /**
     * Returns the world's WorldInfo object
     */
    public WorldInfo getWorldInfo() {
    	return instance.getWorldInfo();
    }
    
    /**
     * Gets the GameRules instance.
     */
    public GameRules getGameRules() {
    	return instance.getGameRules();
    }
    
    /**
     * Updates the flag that indicates whether or not all players in the world are sleeping.
     */
    public void updateAllPlayersSleepingFlag() {
    	instance.updateAllPlayersSleepingFlag();
    }
    
    public float getThunderStrength(float delta) {
    	return instance.getThunderStrength(delta);
    }
    
    /**
     * Sets the strength of the thunder.
     */
    @SideOnly(Side.CLIENT)
    public void setThunderStrength(float strength) {
    	instance.setThunderStrength(strength);
    }
    
    /**
     * Returns rain strength.
     */
    public float getRainStrength(float delta) {
    	return instance.getRainStrength(delta);
    }
    
    /**
     * Sets the strength of the rain.
     */
    @SideOnly(Side.CLIENT)
    public void setRainStrength(float strength) {
    	instance.setRainStrength(strength);
    }
    
    /**
     * Returns true if the current thunder strength (weighted with the rain strength) is greater than 0.9
     */
    public boolean isThundering() {
    	return instance.isThundering();
    }
    
    /**
     * Returns true if the current rain strength is greater than 0.2
     */
    public boolean isRaining() {
    	return instance.isRaining();
    }
    
    /**
     * Check if precipitation is currently happening at a position
     */
    public boolean isRainingAt(BlockPos position) {
    	return instance.isRainingAt(position);
    }
    
    public boolean isBlockinHighHumidity(BlockPos pos) {
    	return instance.isBlockinHighHumidity(pos);
    }
    
    @Nullable
    public MapStorage getMapStorage() {
    	return instance.getMapStorage();
    }
    
    /**
     * Assigns the given String id to the given MapDataBase using the MapStorage, removing any existing ones of the same
     * id.
     */
    public void setData(String dataID, WorldSavedData worldSavedDataIn) {
    	instance.setData(dataID, worldSavedDataIn);
    }
    
    /**
     * Loads an existing MapDataBase corresponding to the given String id from disk using the MapStorage, instantiating
     * the given Class, or returns null if none such file exists.
     */
    @Nullable
    public WorldSavedData loadData(Class <? extends WorldSavedData > clazz, String dataID) {
    	return instance.loadData(clazz, dataID);
    }
    
    /**
     * Returns an unique new data id from the MapStorage for the given prefix and saves the idCounts map to the
     * 'idcounts' file.
     */
    public int getUniqueDataId(String key) {
    	return instance.getUniqueDataId(key);
    }
    
    public void playBroadcastSound(int id, BlockPos pos, int data) {
    	instance.playBroadcastSound(id, pos, data);
    }
    
    public void playEvent(int type, BlockPos pos, int data) {
    	instance.playEvent(type, pos, data);
    }
    
    public void playEvent(@Nullable EntityPlayer player, int type, BlockPos pos, int data) {
    	instance.playEvent(player, type, pos, data);
    }
    
    /**
     * Returns maximum world height.
     */
    public int getHeight() {
    	return instance.getHeight();
    }
    
    /**
     * Returns current world height.
     */
    public int getActualHeight() {
    	return instance.getActualHeight();
    }
    
    /**
     * puts the World Random seed to a specific state dependant on the inputs
     */
    public Random setRandomSeed(int p_72843_1_, int p_72843_2_, int p_72843_3_) {
    	return instance.setRandomSeed(p_72843_1_, p_72843_2_, p_72843_3_);
    }
    
    /**
     * Adds some basic stats of the world to the given crash report.
     */
    public CrashReportCategory addWorldInfoToCrashReport(CrashReport report) {
    	return instance.addWorldInfoToCrashReport(report);
    }
    
    /**
     * Returns horizon height for use in rendering the sky.
     */
    @SideOnly(Side.CLIENT)
    public double getHorizon() {
    	return instance.getHorizon();
    }
    
    public void sendBlockBreakProgress(int breakerId, BlockPos pos, int progress) {
    	instance.sendBlockBreakProgress(breakerId, pos, progress);
    }
    
    /**
     * returns a calendar object containing the current date
     */
    public Calendar getCurrentDate() {
    	return instance.getCurrentDate();
    }
    
    @SideOnly(Side.CLIENT)
    public void makeFireworks(double x, double y, double z, double motionX, double motionY, double motionZ, @Nullable NBTTagCompound compund) {
    	instance.makeFireworks(x, y, z, motionX, motionY, motionZ, compund);
    }
    
    public Scoreboard getScoreboard() {
    	return instance.getScoreboard();
    }
    
    public void updateComparatorOutputLevel(BlockPos pos, Block blockIn) {
    	instance.updateComparatorOutputLevel(pos, blockIn);
    }
    
    public DifficultyInstance getDifficultyForLocation(BlockPos pos) {
    	return instance.getDifficultyForLocation(pos);
    }
    
    public EnumDifficulty getDifficulty() {
    	return instance.getDifficulty();
    }
    
    public int getSkylightSubtracted() {
    	return instance.getSkylightSubtracted();
    }
    
    public void setSkylightSubtracted(int newSkylightSubtracted) {
    	instance.setSkylightSubtracted(newSkylightSubtracted);
    }
    
    @SideOnly(Side.CLIENT)
    public int getLastLightningBolt() {
    	return instance.getLastLightningBolt();
    }
    
    public void setLastLightningBolt(int lastLightningBoltIn) {
    	instance.setLastLightningBolt(lastLightningBoltIn);
    }
    
    public WorldBorder getWorldBorder() {
    	return instance.getWorldBorder();
    }
    
    /**
     * Returns true if the chunk is located near the spawn point
     */
    public boolean isSpawnChunk(int x, int z) {
    	return instance.isSpawnChunk(x, z);
    }
    
    /**
     * Determine if the given block is considered solid on the
     * specified side.  Used by placement logic.
     *
     * @param pos Block Position
     * @param side The Side in question
     * @return True if the side is solid
    */
    public boolean isSideSolid(BlockPos pos, EnumFacing side) {
    	return instance.isSideSolid(pos, side);
    }
    
    /**
     * Determine if the given block is considered solid on the
     * specified side.  Used by placement logic.
     *
     * @param pos Block Position
     * @param side The Side in question
     * @param _default The default to return if the block doesn't exist.
     * @return True if the side is solid
     */
    public boolean isSideSolid(BlockPos pos, EnumFacing side, boolean _default) {
    	return instance.isSideSolid(pos, side, _default);
    }
    
    /**
     * Get the persistent chunks for this world
     *
     * @return
     */
    public com.google.common.collect.ImmutableSetMultimap<net.minecraft.util.math.ChunkPos, net.minecraftforge.common.ForgeChunkManager.Ticket> getPersistentChunks() {
    	return instance.getPersistentChunks();
    }
    
    public Iterator<Chunk> getPersistentChunkIterable(Iterator<Chunk> chunkIterator) {
    	return instance.getPersistentChunkIterable(chunkIterator);
    }
    
    /**
     * Readded as it was removed, very useful helper function
     *
     * @param pos Block position
     * @return The blocks light opacity
     */
    public int getBlockLightOpacity(BlockPos pos) {
    	return instance.getBlockLightOpacity(pos);
    }
    
    /**
     * Returns a count of entities that classify themselves as the specified creature type.
     */
    public int countEntities(net.minecraft.entity.EnumCreatureType type, boolean forSpawnCount) {
    	return instance.countEntities(type, forSpawnCount);
    }
    
    @Deprecated // remove in 1.13
    public void markTileEntitiesInChunkForRemoval(Chunk chunk) {
    	instance.markTileEntitiesInChunkForRemoval(chunk);
    }
    
    public boolean hasCapability(net.minecraftforge.common.capabilities.Capability<?> capability, @Nullable EnumFacing facing) {
    	return instance.hasCapability(capability, facing);
    }
    
    @Nullable
    public <T> T getCapability(net.minecraftforge.common.capabilities.Capability<T> capability, @Nullable EnumFacing facing) {
    	return instance.getCapability(capability, facing);
    }
    
    public MapStorage getPerWorldStorage() {
    	return instance.getPerWorldStorage();
    }
    
    public void sendPacketToServer(Packet<?> packetIn) {
    	instance.sendPacketToServer(packetIn);
    }
    
    public LootTableManager getLootTableManager() {
    	return instance.getLootTableManager();
    }
    
    @Nullable
    public BlockPos findNearestStructure(String p_190528_1_, BlockPos p_190528_2_, boolean p_190528_3_) {
    	return instance.findNearestStructure(p_190528_1_, p_190528_2_, p_190528_3_);
    }
    
}
